package com.sxs.aspectj;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.sxs.annotation.RepeatSubmit;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Aspect //告诉框架我是一个切面类
@Component// 随着框架的启动而启动
@Slf4j
@AllArgsConstructor
public class RepeatSubmitAspect {

    private final RedisTemplate<Object, Object> redisTemplate;

    @Around("@annotation(repeatSubmit)")
    public Object around(ProceedingJoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
        String reqSignature = buildReqSignature(point);
        log.info("请求签名: {}", reqSignature);
        Boolean res = redisTemplate.opsForValue().setIfAbsent(reqSignature, 1, repeatSubmit.interval(), TimeUnit.SECONDS);
        if (!res) {
            return repeatSubmit.message();
        }
        return point.proceed();
    }

    /**
     * 构建请求签名
     *
     * @param joinPoint
     * @return
     */
    private String buildReqSignature(ProceedingJoinPoint joinPoint) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (Objects.isNull(requestAttributes)) {
            throw new RuntimeException("请求参数异常！");
        }
        HttpServletRequest request = requestAttributes.getRequest();
        StringBuilder sb = new StringBuilder();
        for (Object arg : joinPoint.getArgs()) {
            sb.append(arg);
        }
        //请求签名(MD5加密)
        return DigestUtil.md5Hex(StrUtil.format("{}-{}-{}-{}", request.getRemoteAddr(), request.getMethod(), request.getRequestURI(), sb));
    }
}
